-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Runtime polymorphic shapes #238
Conversation
…ConvexHull to ConvexHull.
…e configuration types.
Updates DiskShapeConf configurations to prefer UseRadius over UseVertexRadius.
…ode to avoid loosing coverage.
nice.... mind refreshing the public api docs to reflect changes? |
@ninnghazad I've updated the public API docs now. Sorry about not having done that before. Glad to learn they're being looked at! 😄 Incidentally, do you have a preference for things like names of builder methods, like |
Thanks. Ye, i actually use the API docs. EDIT: Oh, and i just remembered about the *Confs - i'd actually like to keep direct access to the (public) members available - it makes writing serializers easier - using Get/Set i have to write a loader and saver, using direct access (or fetchable reference) i can do with a single function for both. Well i could inject friend-lines into the playrho source - but i would want to avoid that. |
I picked Regarding making serialization easier: I'd like that too. Sounds like methods on the shape configuration classes like What format(s) are you serializing/deserializing to/from? Would full stream I/O support for the More background... At one point I had in mind that a Dropping all of the methods that enforce invariants on the shape configuration classes is more problematic though. Is there a way serialization can be made easier without opening invariants to being compromised? A polygon for example can be openly configured from a public vector of points (vertices). Unfortunately the collision detection and handling code can only handle convex polygons made up of vertices in counter-clockwise order however. Additionally that code uses the normals of the edges that adjacent vertices represent which requires slower calculations like doing square roots. So the code calculates edge normals and caches them along with the vertices. Direct access to all of the shape configuration classes' data member means that these requirements can't be enforced and would have to rely on user discipline making these classes easier to use incorrectly. |
Use/Verb/Naming: I see, and understand your reasoning. For no other reason but personal taste i don't like chaining in c++ - just think it doesn't read well. How about UseThing (or just Thing) for a chaining-version and SetThing for a void-returning classic setter? Compiler would probably do away with the return of the chaining version if it is not used - but i think it's not a bad idea. More work though. I thought about the serialization/access/invariant/initialization stuff. To me it seems to depend on how we imagine playrho is used. There might be direkt and immediate creation of shapes/bodies. Which is where i would expect invariants to be needed, and metadata to be generated. Then there might be different cases of indirect and/or deferred creation of objects. So consider a client server networked game. Client throws a triangle. Through script playrho is called to prepare the triangle and the physics-system spawns it. The same happens on the server upon receiving the client's input event. Now the server simulates the triangle flying for a while and then serializes all relevant state (and probably all information needed to spawn it, in case other clients get to see it). The serialized state gets send to Client which deserializes it and needs to apply the state to its existing triangle, or if needed create the triangle and update it to the supplied state. In that example we have "normal" creation by calling playrho through script, we have creation from serialized definitions/configs and we have updating from serialized state. For the latter cases i would want as much control as possible over what checking and fancy magic happens behind the scenes - the server will never send bad polygons - the invariants have alread made sure of that upon initial creation. For the first case i would want playrho to make sure i scripted up nice shapes so i can be sure of that from there on. Pretty much the same goes for state written to disk and later loaded, although that's less critical. So what i'm trying to say in many words is that creation with rules and enforcement is nice, but raw setting for replication is also needed. stream operators, hm, not sure - in the end i serialize only basic types, so there is control over portability. the serialization in my case is kind of independent from the actual format the data is stored or transmitted in, from a coders perspective. i use https://github.com/USCiLab/cereal and it is awesome. might look like this:
those serialize() up there can save and load, and are real fast at that. they kind of need to be. the load save would work, but would probably recheck vertices. |
Let's take the
I'd thought about doing both before but decided against it. The only reason that sits well for me for having methods besides protecting invariants, is for supporting chaining. From that perspective, that's in part for supporting
I'd not want to stop someone from doing the following though if they're not a fan of chaining and the following is indeed currently possible:
I'm looking at |
Oh wow... I just had an interesting thought regarding the tension between encapsulation and efficiency that's related to this discussion. My reluctance to providing direct access as I mentioned was due to ensuring the protection of invariants. But that interest doesn't extend into other people's code; only to making PlayRho easier to use correctly (and harder to use incorrectly). With this new runtime polymorphic design, I believe there's nothing to stop a user from developing their own shapes within their own namespace so long as all the necessary functions are made available suitably for finding according to C++ name resolution rules. Let's take a custom polygon shape as an example:
Could it be that easy?? LOL, I haven't tried with actual code yet so I'm not certain. Anyways, this also relates to another issue I've been investigating. |
hm. need to let that sink in and think about it over the weekend. hadn't crossed my mind to do custom shapes... hm. |
Description - What's this PR do?
Redesigns the shape classes as a single
Shape
class that is runtime polymorphically configured by shape configuration classes. This new design:Shape
sub-classes. Just callBody::CreateFixture(x)
wherex
is a shape configuration class (like for disks, polygons, etc.).Conf
classes to toplevel configuration classes (DiskShapeConf
,PolygonShapeConf
,ChainShapeConf
,EdgeShapeConf
, andMultiShapeConf
respectively).ShapeVisitor
classes in favor of directly using anystd::function<void(const std::type_info& ti, const void* data)>
compatible code. So the visitor can use code likeif (ti == typeid(DiskShapeConf)) DoIt(*static_cast<const DiskShapeConf*>(data));
(and doesn't need to usedynamic_cast
which can be slower). Note however that free functions onShape
get much of the same information just in a generic form.Shape
.std::make_shared
nor need to know anything aboutstd::shared_ptr
.Joint
andContact
constraints.Related Issues